package com.zmn.oms.third.guomei;

import com.alibaba.fastjson.JSON;
import com.zmn.oms.common.utils.HttpUtil;
import com.zmn.oms.third.guomei.dto.GmqxResultDTO;
import com.zmn.oms.third.guomei.dto.GmqxSyncRequestDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import lombok.SneakyThrows;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Objects;

/**
 * 类描述：生成签名和验证签名等工具类
 *
 * @author xiewenbing
 * @date 2019/12/02 18:30
 */

@Slf4j
public class GmqxUtil {

    public static boolean verifyRequestSign(GmqxSyncRequestDTO requestDTO) {
        if (Objects.isNull(requestDTO) || Objects.isNull(requestDTO.getSign()) || requestDTO.getSign().isEmpty()) {
            return false;
        }

        String appId = Objects.isNull(requestDTO.getAppId()) ? GmqxConsts.APP_ID : requestDTO.getAppId();
        String valueSign = appId + requestDTO.getMsgId() + requestDTO.getMethod() + requestDTO.getData();
        String md5Sign = DigestUtils.md5Hex(valueSign);

        return requestDTO.getSign().compareToIgnoreCase(md5Sign) == 0 ? true : false;
    }

    /**
     * 生成签名
     * @return String
     */
    public static boolean makeRequestSign(GmqxSyncRequestDTO requestDTO) {
        if (Objects.isNull(requestDTO)) {
            return false;
        }

        String appId = Objects.isNull(requestDTO.getAppId()) ? GmqxConsts.APP_ID : requestDTO.getAppId();
        String valueSign = appId + requestDTO.getMsgId() + requestDTO.getMethod() + requestDTO.getData();
        String md5Sign = DigestUtils.md5Hex(valueSign);

        log.info("【{}-API】 消息加密签名内容:[{}]，签名:[{}]", GmqxConsts.CHANNEL_NAME, valueSign, md5Sign);

        requestDTO.setSign(md5Sign.toLowerCase());
        return true;
    }

    /**
     * 给58到家服务发送请求
     * @param requestDTO
     * @return String
     */

    public static GmqxResultDTO sendRequstToGuomeiQingxi(GmqxSyncRequestDTO requestDTO) {

        if (!makeRequestSign(requestDTO)) {
            log.info("【{}-API】 发送请求失败:生成签名失败", GmqxConsts.CHANNEL_NAME);
            return null;
        }

        String pathRequst = String.format(GmqxConsts.REQUEST_PATH,requestDTO.getMethod(),requestDTO.getMsgId(),requestDTO.getSign());
        String urlRequest = GmqxConsts.API_URL + pathRequst;
        String httpResponse;

        try {
            log.info("【{}-API】<API请求> Url:[{}] RequestBody:[{}]", GmqxConsts.CHANNEL_NAME, urlRequest,requestDTO.getData());

            httpResponse = HttpUtil.httpsPost(urlRequest, requestDTO.getData());

            log.info("【{}-API】<API响应> ResponseBody:[{}]", GmqxConsts.CHANNEL_NAME, httpResponse);

        } catch (Exception e) {
            log.info("【{}-API】 请求失败:[{}]", GmqxConsts.CHANNEL_NAME, Objects.nonNull(e) ? e.getMessage():"");
            if (Objects.nonNull(e)) {
                log.error(e.toString());
            }
            return null;
        }

        GmqxResultDTO resultDTO = JSON.parseObject(httpResponse,GmqxResultDTO.class);
        if (Objects.isNull(resultDTO)) {
            log.info("【{}-API】 解析返回数据失败", GmqxConsts.CHANNEL_NAME);
            return null;
        }

        if (resultDTO.getResult().getCode() != GmqxConsts.RESPONSE_CODE_SUCCESS ) {
            log.info("【{}-API】 返回提示错误，错误代码:[{}]，错误提示消息:[{}]", GmqxConsts.CHANNEL_NAME,
                    resultDTO.getResult().getCode(),
                    resultDTO.getResult().getMsg());
        }

        return resultDTO;
    }


    /**
     * 加密
     *
     * @param content  需要加密的内容
     * @param password 加密密码
     * @return 加密结果
     */
    public static String encrypt(String content, String password) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(password.getBytes());
            kgen.init(128, secureRandom);
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            byte[] byteContent = content.getBytes("utf-8");
            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(byteContent);
            return parseByte2HexStr(result); // 加密
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密
     *
     * @param content  待解密内容
     * @param password 解密密钥
     * @return 解密结果
     */
    @SneakyThrows
    public static String decrypt(String content, String password) {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(password.getBytes());
        kgen.init(128, secureRandom);
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
        Cipher cipher = Cipher.getInstance("AES");// 创建密码器
        cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
        byte[] result = cipher.doFinal(parseHexStr2Byte(content));
        return new String(result); // 加密
    }

    /**
     * 将二进制转换为十六进制
     *
     * @param buf 二进制数组
     * @return 十六进制数据
     */
    public static String parseByte2HexStr(byte[] buf) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 将十六进制转换为二进制
     *
     * @param hexStr 十六进制数据
     * @return 二进制数组
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1) {
            return null;
        }
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }
}
